#pragma once
#include<functional>

using namespace std;

namespace wx
{
	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr),
			_pcount(new int(1))
		{}

		template<class D>
		shared_ptr(T* ptr,D del)
			:_ptr(ptr),
			_pcount(new int(1)),
			_del(del)
		{ }

		shared_ptr(const shared_ptr<T>& sp)
		{
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			_del = sp._del;
			*_pcount++;
		}

		void release()
		{
			if (--(*_pcount) == 0)
			{
				_del(_ptr);
				delete _pcount;
			}
		}

		shared_ptr<T>& operator=(shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				release();
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				_del = sp._del;
				*_pcount++;
			}

			return *this;
		}

		~shared_ptr()
		{
			release();
		}

		T* get() const
		{
			return _ptr;
		}

		int use_count() const
		{
			return *_pcount;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		T& operator[](int n)
		{
			return _ptr[n];
		}

	private:
		T* _ptr;
		int* _pcount;
		function<void(T*)> _del = [](T* ptr) {delete ptr; };
	};
}